package com.devops.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Method;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devops.admin.mapper.*;
import com.devops.admin.model.*;
import com.devops.admin.po.*;
import com.devops.admin.service.*;
import com.devops.admin.util.Assert;
import com.devops.admin.util.HelmWrapperUtil;
import com.devops.admin.util.HuHttpUtil;
import com.devops.admin.util.YamlUtils;
import com.devops.admin.vo.*;
import com.devops.constant.DevOpsConstant;
import com.devops.shiro.vm.BaseUserVM;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @ClassNem DOSReleaseServiceImpl
 * @Description
 * @Author heyabo
 * @Date 2022/3/22 14:48
 * @Version 1.0
 **/
@Service
@Slf4j
public class DOSReleaseServiceImpl extends ServiceImpl<DOSReleaseMapper, DOSRelease> implements DOSReleaseService {
    @Autowired
    DOSClusterMapper dosClusterMapper;
    @Autowired
    DOSProjectOutService dosProjectOutService;
    @Autowired
    DOSReleaseOperateLogService dosReleaseOperateLogService;
    @Autowired
    DOSClusterInfoService dosClusterInfoService;
    @Autowired
    DOSClusterNamespaceService dosClusterNamespaceService;
    @Autowired
    DOSHelmChartService dosHelmChartService;
    @Autowired
    DOSEnvTypeService dosEnvTypeService;
    @Autowired
    DOSApplyYamlMapper DOSApplyYamlMapper;
    @Autowired
    DOSKubernetesResourceService dosKubernetesResourceService;
    @Autowired
    DOSK8sResourceEventService dosk8sResourceEventService;
    @Value("${project.similarity.limit}")
    private Double similarityLimit;


    @Override
    public TableResult<DOSReleasePo> getReleases(DOSReleaseVo releaseVo, DOSPageVo pageVo) {
        //获取登录的用户信息
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(null!=user,"该用户未认证");
        if (releaseVo.getReleaseType() == null || releaseVo.getReleaseType() < 1){
            releaseVo.setReleaseType(1);
        }
        if (releaseVo.getEnvType() == null || releaseVo.getEnvType() < 1){
            releaseVo.setEnvType(0);
        }
        Page<DOSReleasePo> page = new Page<>(pageVo.getPageNum(),pageVo.getPageSize());
        TableResult<DOSReleasePo> tableResult = new TableResult<>();
        List<DOSReleasePo> releasePos;
        if (!user.getAdminRole()) {
            // 如果是管理员级别以下的用户，则需要根据自己所在的项目组，或者项目查看相应的release
            DOSProjectVo projectVo = DOSProjectVo.builder()
                            .userId(user.getId()).build();
            List<DOSProjectPo> projects = dosProjectOutService.getProjects(projectVo);
            // 如果项目列表为空则表明当前用户不可查看release列表
            if (CollectionUtil.isEmpty(projects) || projects.size() < 1){
                return tableResult;
            }
            // 获取项目id列表并去重
            List<Integer> projectIds = projects.stream().map(DOSProjectPo::getId).distinct().collect(Collectors.toList());
            releaseVo.setProjectIds(projectIds);
            releasePos = baseMapper.getReleasePageForGeneralUser(page,releaseVo);
        }else{
            // 查询管理员级别能看到的release列表
            releasePos = baseMapper.selectReleasePage(page, releaseVo);
        }
        // 查询release的image和imageTag
//        releasePos.forEach(releasePo -> {
//            String imageTag = this.getImageTag(DOSReleaseValuesVo.builder().releaseId(releasePo.getId())
//                    .releaseType(1)
//                    .release(releasePo.getReleaseName())
//                    .namespace(releasePo.getNamespace()).build());
//            if (StrUtil.isNotEmpty(imageTag)) {
//                releasePo.setImage(imageTag);
//            }
//        });
        Pagination p = Pagination.builder().pageNum(page.getCurrent()).pageSize(page.getSize()).total(page.getTotal()).build();
        tableResult.setPagination(p);
        tableResult.setList(releasePos);

        return tableResult;
    }

    /**
     * 此方法不对外提供服务 仅支持release安装成功后的保存数据
     */
    public int saveRelease(DOSReleaseParamVo param) {
        DOSRelease release = DOSRelease.builder()
                .releaseName(param.getRelease())
                .projectId(param.getProjectId())
                .chartId(param.getChartId())
                .revision(param.getRevision())
                .envType(param.getEnvType())
                .clusterId(param.getClusterId())
                .namespaceId(param.getNamespaceId())
                .chartTag(param.getChartTag())
                .releaseType(DevOpsConstant.ReleaseType.HELM)
                .build();

        this.save(release);
        return release.getId();
    }

    @Override
    public DOSValuePo getValues(DOSReleaseValuesVo valuesVo) {
        String data = "data";
        Assert.isTrue(null!=valuesVo.getReleaseId() && valuesVo.getReleaseId() >0,"releaseId不能为空");
        Assert.isTrue(null!=valuesVo.getReleaseType() && valuesVo.getReleaseType() > 0,"releaseType不能为空");
        DOSValuePo valuePo = new DOSValuePo();
        if (valuesVo.getReleaseType() != null && valuesVo.getReleaseType().intValue() == DevOpsConstant.ReleaseType.YAML){
            // 查询yaml部署的value信息
            DOSApplyYaml applyYaml = DOSApplyYamlMapper.getLabels(valuesVo.getReleaseId());
            valuePo.setCode(1);
            valuePo.setValue(applyYaml.getYamlValue());
        } else {
            // 查询helm部署的value信息
            Assert.isTrue(null!=valuesVo.getRelease(),"release不能为空");
            Assert.isTrue(null!=valuesVo.getNamespace(),"命名空间不能为空");

            getHelmReleaseValue(valuesVo, data, valuePo);
            setReversion(valuesVo.getReleaseId(), null,null);
        }

        return valuePo;
    }

    private void getHelmReleaseValue(DOSReleaseValuesVo valuesVo, String data, DOSValuePo valuePo) {
        DOSRelease dosRelease = this.getById(valuesVo.getReleaseId());
        String helmChartUrl;
        if (dosRelease.getClusterId() != null && dosRelease.getClusterId() > 0) {
            Assert.isTrue(dosRelease.getId() != null && dosRelease.getId() > 0, "release数据异常");
            helmChartUrl = this.getHelmUrl(dosRelease.getClusterId());
        }else {
            helmChartUrl = dosClusterMapper.getHelmWrapperApiUrlByRelease(dosRelease.getId());
        }
        Assert.isTrue(StrUtil.isNotBlank(helmChartUrl),"未查询到url地址");

        String api = DevOpsConstant.HelmWrapperAPIUrl.HELM_VALUES_GET;
        api = StrUtil.replace(api,":namespace", valuesVo.getNamespace());
        api = StrUtil.replace(api,":release", valuesVo.getRelease());
        Map<String,Object> map = new HashMap<>(16);
        if (valuesVo.getRevision() != null && valuesVo.getRevision() > 0) {
            map.put("revision", valuesVo.getRevision());
        }
        String url = (helmChartUrl + api).replaceAll(" ","");
        JSONObject json = HuHttpUtil.dealHttpAndResponse(Method.GET,url.trim(),map,null);
        if(json.containsKey(data)){
            valuePo.setValue(json.getStr(data));
            valuePo.setCode(1);
        }else {
            valuePo.setCode(-1);
        }
    }

    @Override
    public List<DOSReleasePo> getReleases(DOSReleaseVo releaseVo) {
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        Assert.isTrue(releaseVo.getProjectId() != null && releaseVo.getProjectId() > 0,"projectId不能为空");
        if (user == null) {
            return null;
        }
        if (!user.getAdminRole()) {
            // 如果是管理员级别一下的用户，则需要根据自己所在的项目组，或者项目查看相应的release
            DOSProjectVo projectVo = DOSProjectVo.builder()
                    .userId(user.getId()).build();
            List<DOSProjectPo> projects = dosProjectOutService.getProjects(projectVo);
            // 如果项目列表为空则表明当前用户不可查看release列表
            if (CollectionUtil.isEmpty(projects) || projects.size() < 1){
                return null;
            }
            // 获取项目id列表并去重
            List<Integer> projectIds = projects.stream().map(DOSProjectPo::getId).distinct().collect(Collectors.toList());
            if (projectIds.contains(releaseVo.getProjectId())) {
                releaseVo.setProjectIds(projectIds);
            }else {
                return null;
            }
        }
        List<DOSReleasePo> dosReleasePos = baseMapper.selectReleaseListByProjectIdAndEnvType(releaseVo);
        // 查询release的image和imageTag
//        dosReleasePos.forEach(releasePo -> {
//            String imageTag = this.getImageTag(DOSReleaseValuesVo.builder().releaseId(releasePo.getId())
//                    .releaseType(1)
//                    .release(releasePo.getReleaseName())
//                    .namespace(releasePo.getNamespace()).build());
//            if (StrUtil.isNotEmpty(imageTag)) {
//                releasePo.setImage(imageTag);
//            }
//        });
        return dosReleasePos;
    }



    @Override
    public DOSReleasePo getReleaseDetailById(Integer releaseId) {
        DOSReleasePo dosReleasePo;
        if ((dosReleasePo = this.baseMapper.getReleaseDetailById(releaseId)) != null
                && StrUtil.isNotBlank(dosReleasePo.getChartRepositoryName())
                && StrUtil.isNotBlank(dosReleasePo.getChartName())) {
            dosReleasePo.setRepoHelmName(dosReleasePo.getChartRepositoryName() + "/" + dosReleasePo.getChartName());
        }

        return dosReleasePo;
    }

    /**
     * 安装release
     * 必传的参数 projectId,clusterId,namespaceId,chartId,release,envType
     */
    @Override
    public DOSHelmOperationPo installReleaseByRepoChart(DOSReleaseParamVo param) {
        //集群校验
        Assert.isTrueMvc(param.getClusterId() != null && param.getClusterId() > 0,"集群id不能为空");

        //命名空间校验
        Assert.isTrueMvc(param.getNamespaceId() != null && param.getNamespaceId() > 0,"命名空间id不能为空");
        DOSClusterNamespace clusterNamespace = dosClusterNamespaceService.getById(param.getNamespaceId());
        Assert.isTrueMvc(clusterNamespace != null && StrUtil.isNotBlank(clusterNamespace.getNamespace()),"命名空间数据异常");
        param.setNamespace(clusterNamespace.getNamespace());

        //chart校验
        Assert.isTrueMvc(param.getChartId() != null && param.getChartId() > 0,"chartId不能为空");
        DOSHelmChart chart = dosHelmChartService.getById(param.getChartId());
        Assert.isTrueMvc(chart != null && StrUtil.isNotBlank(chart.getChartName())
                && StrUtil.isNotBlank(chart.getChartRepositoryName())
                && StrUtil.isNotBlank(chart.getChartTag()),"chart数据异常");
        param.setRepoHelmName(chart.getChartRepositoryName() + "/" + chart.getChartName());
        //release校验
        Assert.isTrueMvc(checkReleaseName(param.getRelease()),"release命名不规范");
        // 检查名字的相似度
        if (param.getCheckType() == 0) {
            List<String> similarityReleaseName = baseMapper.getReleaseNameSimilarity(param.getRelease(),similarityLimit);
            Assert.isSimilar(ObjectUtil.isEmpty(similarityReleaseName), param.getRelease()+"与" + StringUtils.join(similarityReleaseName, ",") + "相似度较高，是否保存");
        }

        //envType校验
        Assert.isTrueMvc(dosEnvTypeService.validEnvType(param.getEnvType()), "envType数据异常");

        // 校验release的唯一性
        Assert.isTrue(count(Wrappers.<DOSRelease>lambdaQuery()
                .eq(DOSRelease::getClusterId,param.getClusterId())
                .eq(DOSRelease::getNamespaceId,param.getNamespaceId())
                .eq(DOSRelease::getReleaseName,param.getRelease())) < 1,"同一集群的同一命名空间存在相同名称的release");

        //安装 公共方法里包含projectId的校验
        return installOrUpgrade(param,DevOpsConstant.ReleaseOperationFlag.INSTALL);
    }

    /**
     * release的升级
     * 仅releaseId为必须参数
     */
    @Override
    public DOSHelmOperationPo upgradeReleaseByRepoChart(DOSReleaseParamVo param) {
        //参数校验 这里只校验了releaseId
        Assert.isTrueMvc(param.getReleaseId() != null && param.getReleaseId() > 0,"releaseId不能为空");

        DOSReleasePo releasePo = this.baseMapper.getReleaseDetailById(param.getReleaseId());
        Assert.isTrueMvc(releasePo != null
                && StrUtil.isNotBlank(releasePo.getReleaseName())
                && releasePo.getProjectId() != null
                && releasePo.getProjectId() > 0
                && releasePo.getClusterId() != null
                && releasePo.getClusterId() > 0
                && StrUtil.isNotBlank(releasePo.getNamespace())
                && StrUtil.isNotBlank(releasePo.getChartRepositoryName())
                && StrUtil.isNotBlank(releasePo.getChartName()),"release数据异常");

        param.setRelease(releasePo.getReleaseName());
        param.setProjectId(releasePo.getProjectId());
        param.setClusterId(releasePo.getClusterId());
        param.setNamespace(releasePo.getNamespace());
        param.setRepoHelmName(releasePo.getChartRepositoryName() + "/" + releasePo.getChartName());
        DOSRelease byId = this.getById(param.getReleaseId());
        if (byId.getReleaseName().equals(param.getRelease()) && param.getCheckType() == 0){
            // 检查名字的相似度
            List<String> similarityReleaseName = baseMapper.getReleaseNameSimilarity(param.getRelease(),similarityLimit);
            Assert.isSimilar(ObjectUtil.isEmpty(similarityReleaseName), param.getRelease()+"与" + StringUtils.join(similarityReleaseName, ",") + "相似度较高，是否修改");
        }

        //升级
        return installOrUpgrade(param,DevOpsConstant.ReleaseOperationFlag.UPGRADE);
    }

    @Override
    public DOSHelmOperationPo historyRelease(DOSReleaseParamVo param) {

        return historyOrRollBackOrUninstall(param,DevOpsConstant.ReleaseOperationFlag.HISTORY);
    }

    @Override
    public DOSHelmOperationPo rollbackRelease(DOSReleaseParamVo param) {
        return historyOrRollBackOrUninstall(param,DevOpsConstant.ReleaseOperationFlag.ROLLBACK);
    }

    @Override
    public DOSHelmOperationPo uninstallRelease(DOSReleaseParamVo param) {
        return historyOrRollBackOrUninstall(param,DevOpsConstant.ReleaseOperationFlag.UNINSTALL);
    }

    @Override
    public List<HashMap<String,Object>> getGroupRelease() {

        return baseMapper.getGroupRelease();
    }

    @Override
    public void checkRestartPermission(Integer releaseId) {
        Assert.isTrueMvc(releaseId != null && releaseId > 0,"releaseId不能为空");
        DOSRelease release = getById(releaseId);
        Assert.isTrueMvc(release != null,"release不存在");
        Assert.isTrueMvc(release.getEnvType().intValue() == DevOpsConstant.EnvType.UAT,"只能重启uat环境的release");
    }

    @Override
    public List<DOSReleasePo> getReleasesByProjectId(Integer projectId) {

        return baseMapper.getReleaseByProjectId(projectId);
    }

    @Override
    public String getImageTag(DOSReleaseValuesVo valuesVo) {
        DOSValuePo values = this.getValues(valuesVo);
        String image = null;
        String tag = null;
        if (values != null && StrUtil.isNotBlank(values.getValue())){
            if (valuesVo.getReleaseType().intValue() == DevOpsConstant.ReleaseType.HELM) {
                // 查询release文件的image和tag
                image = (String) YamlUtils.getValues("image.repository", values.getValue());
                tag = (String) YamlUtils.getValues("image.tag", values.getValue());

            }
        }

        return StrUtil.isEmpty(image) && StrUtil.isEmpty(tag) ? null : image + ":"+tag;
    }

    @Override
    public List<DOSReleasePo> selectReleaseListByProjectIdAndEnvType(DOSReleaseVo releaseVo) {

        return baseMapper.selectReleaseListByProjectIdAndEnvType(releaseVo);
    }


    public DOSHelmOperationPo installOrUpgrade(DOSReleaseParamVo param,int type) {
        //type 校验
        Assert.isTrueMvc(type == DevOpsConstant.ReleaseOperationFlag.INSTALL
                || type == DevOpsConstant.ReleaseOperationFlag.UPGRADE,"不支持的操作类型");
        //用户操作权限校验
        Assert.isTrueMvc(checkAuthPermissions(param.getProjectId()),"没有操作权限");

        //helmWrapperDomain获取
        String helmWrapperDomain = getHelmUrl(param.getClusterId());

        //helmWrapper服务可用性校验
        HelmWrapperUtil.checkHelmWrapperServiceUrl(helmWrapperDomain);

        //获取登录的用户信息 操作日志封装
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        DOSReleaseOperateLog operateLog = new DOSReleaseOperateLog();
        operateLog.setOperateValues(StrUtil.isNotBlank(param.getValues()) ? param.getValues() : "");
        operateLog.setOperateUserId(user.getId());
        operateLog.setOperateType(type);

        //方法返回值初始化
        DOSHelmOperationPo operationPo = new DOSHelmOperationPo();

        //更新远程仓库
        String helmRepoUpdateUrl = helmWrapperDomain
                + DevOpsConstant.HelmWrapperAPIUrl.HELM_REPO_UPDATE_PUT;
        JSONObject updateJson = HuHttpUtil.dealHttpAndResponse(Method.PUT,helmRepoUpdateUrl,null,null);
        Assert.isTrueMvc(updateJson.getInt("code") == 0,"远程仓库更新失败，请稍后重试！");

        //查询远程仓库 chart是否唯一存在
        checkChart(param, helmWrapperDomain);

        //操作开始 api处理 也就是因为这两者的api地址相似 才把它们封装成一个公共方法
        String api = type == DevOpsConstant.ReleaseOperationFlag.INSTALL
                ? DevOpsConstant.HelmWrapperAPIUrl.HELM_INSTALL_POST
                : DevOpsConstant.HelmWrapperAPIUrl.HELM_UPGRADE_PUT;
        api = api.replace(":chart",param.getRepoHelmName())
                .replace(":namespace",param.getNamespace())
                .replace(":release",param.getRelease())
                .trim();
        String url = (helmWrapperDomain + api).trim();

        //body封装
        JSONObject bodyJson = new JSONObject();
        if (StrUtil.isNotBlank(param.getChartTag()) && !"latest".equals(param.getChartTag())) {
            bodyJson.set("version",param.getChartTag());
        }
        if (StrUtil.isNotBlank(param.getValues())) {
            bodyJson.set("values", param.getValues());
        }

        //调用helm-wrapper服务
        JSONObject json = HuHttpUtil.dealHttpAndResponse(type == DevOpsConstant.ReleaseOperationFlag.INSTALL ? Method.POST : Method.PUT,
                url,bodyJson.toString());
        // 设置chartTag
        if (StrUtil.isEmpty(param.getChartTag())){
            param.setChartTag("latest");
        }
        //处理返回结果
        if (json.getInt("code") == 0) {
            //操作成功
            operateLog.setOperateResult("操作成功: "+json.getStr("data"));
            int releaseId;
            if (type == DevOpsConstant.ReleaseOperationFlag.INSTALL) {
                //新部署的release revision设置为1
                param.setRevision(1);
                //添加release release保存数据库
                releaseId = saveRelease(param);
                operationPo.setReleaseId(releaseId);
                saveReleaseImage(releaseId);
            } else {
                //升级时更新release的reversion
                setReversion(param.getReleaseId(), helmWrapperDomain,param.getChartTag());
                releaseId = param.getReleaseId();
                saveReleaseImage(releaseId);
            }
            operateLog.setReleaseId(releaseId);
            dosReleaseOperateLogService.save(operateLog);
            operationPo.setCode(0);
            operationPo.setMessage("操作成功");

        } else { //操作失败
            String error = json.getStr("error");
            operateLog.setOperateResult("操作失败:"+error);
            dosReleaseOperateLogService.save(operateLog);
            operationPo.setCode(1);
            operationPo.setError(json.getStr("error"));
            //安装失败 卸载release 不讨论返回结果
            if (type == DevOpsConstant.ReleaseOperationFlag.INSTALL) {
                String uninstallUrl = (helmWrapperDomain +
                        DevOpsConstant.HelmWrapperAPIUrl.HELM_UNINSTALL_DELETE
                                .replace(":namespace", param.getNamespace())
                                .replace(":release", param.getRelease()
                                        .trim())).trim();
                HuHttpUtil.dealHttpAndResponse(Method.DELETE,uninstallUrl,null,null);
            }
        }

        return operationPo;
    }

    private void saveReleaseImage(int releaseId) {
        DOSReleasePo releasePo = this.getReleaseDetailById(releaseId);
        DOSReleaseValuesVo releaseValuesVo = DOSReleaseValuesVo.builder().releaseId(releaseId)
                .releaseType(1)
                .release(releasePo.getReleaseName())
                .namespace(releasePo.getNamespace()).build();
        String imageTag = this.getImageTag(releaseValuesVo);
        if (StrUtil.isNotEmpty(imageTag)) {
            this.updateById(DOSRelease.builder().id(releaseId).image(imageTag).build());
        }
    }

    /**
     * @Author heyabo
     * @Description 检查chart是否合法
     * @Date 15:13 2022/8/22
     * @Param [param, helmWrapperDomain]
     **/
    private void checkChart(DOSReleaseParamVo param, String helmWrapperDomain) {
        String helmSearchUrl = DevOpsConstant.HelmWrapperAPIUrl.HELM_SEARCH_REPO_VERSION_GET;
        String helmSearchRepoApi;
        if (StrUtil.isNotBlank(param.getChartTag()) && !"latest".equals(param.getChartTag())){
            helmSearchRepoApi = helmSearchUrl.replace(":keyword", param.getRepoHelmName())
                    .replace(":version", param.getChartTag());
        }else {
            helmSearchUrl = DevOpsConstant.HelmWrapperAPIUrl.HELM_SEARCH_REPO_GET;
            helmSearchRepoApi = helmSearchUrl.replace(":keyword", param.getRepoHelmName());
        }
        String helmSearchRepoUrl = helmWrapperDomain + helmSearchRepoApi;
        JSONObject searchJson = HuHttpUtil.dealHttpAndResponse(helmSearchRepoUrl);
        int code = searchJson.getInt("code");
        JSONArray data = searchJson.getJSONArray("data");
        Assert.isTrueMvc(code == 0 && data != null && data.size() > 0,"请检查远程仓库的chart");
    }

    /**
     * 查询历史，回滚和卸载方法
     */
    public DOSHelmOperationPo historyOrRollBackOrUninstall(DOSReleaseParamVo param, int type) {

        Assert.isTrueMvc(type == DevOpsConstant.ReleaseOperationFlag.UNINSTALL
                || type == DevOpsConstant.ReleaseOperationFlag.ROLLBACK
                || type == DevOpsConstant.ReleaseOperationFlag.HISTORY,"操作类型错误");
        //入参校验
        Assert.isTrueMvc(param.getReleaseId() != null && param.getReleaseId() > 0,"releaseId不能为空");
        DOSReleasePo releasePo = this.baseMapper.getReleaseDetailById(param.getReleaseId());
        Assert.isTrueMvc(releasePo != null
                && StrUtil.isNotBlank(releasePo.getReleaseName())
                && releasePo.getProjectId() != null
                && releasePo.getProjectId() > 0
                && releasePo.getClusterId() != null
                && releasePo.getClusterId() > 0
                && StrUtil.isNotBlank(releasePo.getNamespace()), "release数据异常");

        param.setRelease(releasePo.getReleaseName());
        param.setProjectId(releasePo.getProjectId());
        param.setClusterId(releasePo.getClusterId());
        param.setNamespace(releasePo.getNamespace());

        Assert.isTrue(checkAuthPermissions(param.getProjectId()),"没有操作的权限");

        //获取登录的用户信息
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        //操作日志
        DOSReleaseOperateLog operateLog = new DOSReleaseOperateLog();
        operateLog.setReleaseId(param.getReleaseId());
        operateLog.setOperateValues(StrUtil.isNotBlank(param.getValues()) ? param.getValues() : "");
        operateLog.setOperateUserId(user.getId());
        operateLog.setOperateType(type);
        //方法返回值初始化
        DOSHelmOperationPo operationPo = new DOSHelmOperationPo();
        String api;
        Method method;
        if (type == DevOpsConstant.ReleaseOperationFlag.UNINSTALL) {
            //删除
            api = DevOpsConstant.HelmWrapperAPIUrl.HELM_UNINSTALL_DELETE;
            method = Method.DELETE;

        } else if (type == DevOpsConstant.ReleaseOperationFlag.ROLLBACK) {
            Assert.isTrueMvc(param.getRevision() != null && param.getRevision() > 0,"revision不能为空");
            //回滚
            api = DevOpsConstant.HelmWrapperAPIUrl.HELM_ROLLBACK_PUT.replace(":reversion",param.getRevision().toString());
            method = Method.PUT;
        } else {
            //历史
            api = DevOpsConstant.HelmWrapperAPIUrl.HELM_HISTORY_GET;
            method = Method.GET;
        }
        //helmWrapperDomain
        String helmWrapperDomain = getHelmUrl(param.getClusterId());
        //helmWrapper服务可用性校验
        HelmWrapperUtil.checkHelmWrapperServiceUrl(helmWrapperDomain);

        String url = (helmWrapperDomain + api
                .replace(":namespace",param.getNamespace())
                .replace(":release",param.getRelease())
                .trim()).trim();

        JSONObject json = HuHttpUtil.dealHttpAndResponse(method,url,null,null);

        if (json.getInt("code") == 0) {
            //操作成功
            operationPo.setCode(0);
            operateLog.setOperateResult("操作成功");
            dosReleaseOperateLogService.save(operateLog);
            //历史
            if (type == DevOpsConstant.ReleaseOperationFlag.HISTORY) {
                JSONArray jsonArray = JSONUtil.parseArray(json.getStr("data"));
                List<DOSHelmEntity> dosHelmEntities = jsonArray.toList(DOSHelmEntity.class);
                //排序
                List<DOSHelmEntity> entityList = dosHelmEntities.stream().sorted(Comparator.comparing(DOSHelmEntity::getRevision).reversed()).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(entityList) && entityList.size() > 0) {
                    //查询values
                    String values = queryValues(param, helmWrapperDomain);
                    entityList.get(0).setValues(values);
                    operationPo.setHelmEntities(entityList);
                    // 根据id获取release然后更新revision
                    DOSRelease release = this.getById(param.getReleaseId());
                    release.setRevision(entityList.get(0).getRevision());
                    this.updateById(release);
                }
            } else if (type == DevOpsConstant.ReleaseOperationFlag.UNINSTALL) {
                //卸载
                removeById(param.getReleaseId());
                operationPo.setMessage("卸载成功");
            } else { //回滚
                setReversion(param.getReleaseId(), helmWrapperDomain,null);
                operationPo.setMessage("回滚成功");
            }
        } else { //操作失败
            operateLog.setOperateResult("操作失败");
            dosReleaseOperateLogService.save(operateLog);
            operationPo.setCode(1);
            operationPo.setError(json.getStr("error"));
        }

        return operationPo;
    }

    /**
     * @Author heyabo
     * @Description 对比release的reversion并更新
     * @Date 19:04 2022/8/15
     * @Param [releaseId, helmWrapperDomain]
     **/
    private void setReversion(Integer releaseId, String helmWrapperDomain,String chartTag) {
        DOSRelease release = this.getById(releaseId);
        if (StrUtil.isEmpty(helmWrapperDomain)){
            //helmWrapperDomain获取
            helmWrapperDomain = getHelmUrl(release.getClusterId());
        }
        DOSClusterNamespace namespace = dosClusterNamespaceService.getById(release.getNamespaceId());
        String api;
        Method method;
        api = DevOpsConstant.HelmWrapperAPIUrl.HELM_HISTORY_GET;
        method = Method.GET;
        api = StrUtil.replace(api,":namespace", namespace.getNamespace());
        api = StrUtil.replace(api,":release", release.getReleaseName());
        String urls = (helmWrapperDomain + api).replaceAll(" ","");
        JSONObject jsons = HuHttpUtil.dealHttpAndResponse(method, urls.trim(),null,null);
        int reversion;
        if (jsons.getInt("code") == 0) {
            JSONArray jsonArray = JSONUtil.parseArray(jsons.getStr("data"));
            List<DOSHelmEntity> dosHelmEntities = jsonArray.toList(DOSHelmEntity.class);
            if (CollectionUtil.isNotEmpty(dosHelmEntities) && dosHelmEntities.size() > 0){
                //排序
                List<DOSHelmEntity> entityList = dosHelmEntities.stream().sorted(Comparator.comparing(DOSHelmEntity::getRevision).reversed()).collect(Collectors.toList());
                reversion = entityList.get(0).getRevision();
                if(reversion != release.getRevision()){
                    release.setRevision(reversion);
                    if (StrUtil.isNotBlank(chartTag)){
                        release.setChartTag(chartTag);
                    }
                    this.updateById(release);
                }
            }

        }
    }

    private String queryValues(DOSReleaseParamVo param, String helmWrapperDomain) {
        String api = StrUtil.replace(DevOpsConstant.HelmWrapperAPIUrl.HELM_VALUES_GET,":release", param.getRelease());
        String url = (helmWrapperDomain + StrUtil.replace(api,":namespace",param.getNamespace())).replaceAll(" ","");
        JSONObject json = HuHttpUtil.dealHttpAndResponse(Method.GET,url.trim(),null,null);
        String values = "";
        if (json.getInt("code") == 0){
            JSONObject data = JSONUtil.parseObj(json.getStr("data"));
            values = JSONUtil.toJsonStr(data);
        }

        return values;
    }

    /**
     * @Author heyabo
     * @Description 获取helmUrl
     * @Date 08:50 2022/3/25
     * @Param [projectId]
     * @return java.lang.String
     **/
    private String getHelmUrl(int clusterId){
        return dosClusterMapper.getHelmChartUrl(clusterId);
    }

    /**
     * @Author heyabo
     * @Description 校验release的命名规则
     * @Date 11:52 2022/4/7
     * @Param [release]
     * @return boolean
     **/
    private boolean checkReleaseName(String release) {
        String code = "[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*";
        Pattern p1 = Pattern.compile(code);
        Matcher m1 = p1.matcher(release);
        return m1.matches();
    }

    /**
     * @Author heyabo
     * @Description 校验当前登录人员是否有操作的权限
     * @Date 18:48 2022/4/19
     * @Param [prijectId]
     * @return boolean
     **/
    private boolean checkAuthPermissions(Integer projectId) {
        Assert.isTrueMvc(projectId != null && projectId > 0,"projectId不能为空");
        //获取登录的用户信息
        BaseUserVM user = (BaseUserVM) SecurityUtils.getSubject().getPrincipal();
        if (user.getAdminRole()){
            return true;
        }
        //获取当前用户下的项目列表
        DOSProjectVo vo = new DOSProjectVo();
        vo.setUserId(user.getId());
        List<DOSProjectPo> projects = dosProjectOutService.getProjects(vo);
        for (DOSProjectPo project : projects) {
            if (project.getId() == projectId.intValue()) {
                return true;
            }
        }

        return false;
    }
}
